<!-- 
/*
    初始状态pending
    res，rej初始值null
    空回调数组（失败和成功的）
    两个方法，成功和失败的
    try -> 参数fn调用，catch -> 失败方法调用

    成功和失败方法：改状态，赋值res或rej，forrach对应数组并在里面调用回调
*/
function MyPromise (func) {
  var self = this;
  self.status = 'pending';    //进来时就先定义一个'pending'状态；等待调用时改变状态；
  self.resolveValue = null;   //MyPromise增加两个变量，方便之后储存参数；
  self.rejectReason = null;
  //完成异步操作：
  self.ResolveCallBackList = [];  //存储注册时成功的函数；
  self.RejectCallBackList = [];   //存储失败时成功的函数；
  //完成MyPromise的两个方法：
  function resolve (value) {      //成功的方法；
      if (self.status === 'pending') {
          self.status = 'Fulfilled';      //成功回调触发'Fulfilled'状态；
          self.resolveValue = value;      //把传入的'value'形参存到MyPromise中；方便调用.then()时有该参数；
          self.ResolveCallBackList.forEach(function (ele) { //调用时可执行异步操作；；
              ele();
          });
      }
  };
  function reject (reason) {      //失败的方法；
      if (self.status === 'pending') {
          self.status = 'Rejected';       //失败回调触发'Rejected'状态；
          self.rejectReason = reason;
          self.RejectCallBackList.forEach(function (ele) { //调用时可执行异步操作；
              ele();
          });
      }
  }
  //同步执行时抛出错误后的兼容：
  try {                           //当抛出错误后直接执行失败的回调函数；
      func(resolve, reject);      //创建MyPromise时就同步执行；
  }catch(e){
      reject(e)
  }
};

//解决ruturn值的方法:
function ResolutionReturnPronise (nextPromise, returnValue, res, rej) {
    //可以利用，之后的.then()注册的回调函数，都是注册在nextPromise身上的这一特点巧妙处理；
    if (returnValue instanceof MyPromise) {  //返回值为Promise时：
        returnValue.then(function (val) {    //直接让返回值链式调用.then()方法
            res(val);                        //方法中成功方法直接执行成功回调；
        }, function (reason) {
            rej(reason);                     //失败方法直接执行失败回调；
        })

    }else{                                   //返回值为普通值时
        res(returnValue);                    //会执行成功的回调：
    }

}

/*
    判断两个fn回调是不是存在，不存在直接fn返回val参数
    初始化pros存起来比如叫pros0，

    //
    
    成功状态的话走定时，try,catch，

    try里面将成功回调的fn调用，并传上面拿到的成功的值进去，并把这个存起来
    然后存起来的这个东西instanceOf _Promise是true
    如果为true就走pros0的then方法，里面两个回调，then的成功和失败，否则就直接走成功方法

    catch里面直接走失败方法

    失败状态时同上

    //

    如果是等待状态,把上面的队列直接push到对应的回调数组那里去

    最后return pros出来

*/

//完善.then()方法：
MyPromise.prototype.then = function (func1, func2) {  //原方法可插入成功和失败两个方法；
    //处理空then()：
    if (!func1) {    //如果为空将参数原封不用返回；
        func1 = function (val) {
            return val;
        }
    }
    if (!func2) {    //如果为空将错误原封不动返回；
        func2 = function (reason) {
            throw new Error(reason);
        }
    }
    var self = this;
    //实现原方法调用.then()方法是返回的是一个属性Promise对象；
    var nextPromise = new MyPromise(function (res, rej) {
    //完成同步操作：
        if (self.status === 'Fulfilled') {
            //.then()本身是异步操作：由于没有微任务权限，这里用setTimeout()使每一步为异步操作:
            setTimeout(function () {
                //完善数据捕获功能；(无论错误出现在成功还是失败中都会在失败的回调中找出)
                try{
                    // var nextResolveValue = func1(self.resolveValue);
                    // //原方法返回一个普通值时会执行成功的回调：
                    // res(nextResolveValue);
                    var nextResolveValue = func1(self.resolveValue);
                    ResolutionReturnPronise(nextPromise, nextResolveValue, res, rej);//由于异步执行，此处nextPromise可以直接传进去；
                }catch(e){
                    rej(e);
                }
            }, 0);

        }
        if (self.status === 'Rejected') {
            setTimeout(function () {
                  try{                   //完善数据捕获功能；
                        var nextRejectValue = func2(self.rejectReason);
                        // res(nextRejectValue); //原方法返回一个普通值时会执行成功的回调；
                        ResolutionReturnPronise(nextPromise, nextRejectValue, res, rej);
                    }catch(e){
                        rej(e);
                    }
            }, 0);
        }
        //完成异步操作：
        if (self.status === 'pending') {                //如果状态为'pending'
            self.ResolveCallBackList.push(function () { //注册成功函数时放到成功回调数组中；
                setTimeout(function () {
                    try{                   //完善数据捕获功能；
                        var nextResolveValue = func1(self.resolveValue);
                        // res(nextResolveValue); //原方法返回一个普通值时会执行成功的回调；
                        ResolutionReturnPronise(nextPromise, nextResolveValue, res, rej);
                    }catch(e){
                        rej(e);
                    }
                }, 0);

            });
            self.RejectCallBackList.push(function () {  //注册失败函数时放到成功回调数组中；
                setTimeout(function () {
                    try{                   //完善数据捕获功能；
                        var nextRejectValue = func2(self.rejectReason);
                        // res(nextRejectValue); //原方法返回一个普通值时会执行成功的回调；
                        ResolutionReturnPronise(nextPromise, nextRejectValue, res, rej);
                    }catch(e){
                        rej(e);
                    }
                }, 0);
            });
        }
    });
    //完成链式调用：
    return nextPromise;  //要知道：之后的.then()注册的回调函数，都是注册在nextPromise身上的；
};

//完善.race()方法：
MyPromise.race = function (promiseArr) {
    return new MyPromise(function (resolve, reject){
        promiseArr.forEach(function (promise, index){
            promise(resolve, reject);     //哪个状态最先改变一定会先触发；
        });
    });
};

//完善.all()方法：
MyPromise.all = function (promiseArr) {
    return new MyPromise(function (resolve, reject){
        if(!Array.isArray(promiseArr)){
            return reject(new TypeError("argument must be anarray"));
        }
        var countNum = 0;
        var promiseNum = promiseArr.length;
        var resolvedvalue = new Array(promiseNum);
        for(var i = 0; i < promiseNum; i++){
            (function (i) {
                promiseArr[i].then(function (value) {  //对每一个数组中的Promise对象进行单独.then();
                    countNum++;
                    resolvedvalue[i] = value;
                    if(countNum === promiseNum){
                        return resolve(resolvedvalue)  //全部成功时，输出所有的已存到数组中的结果；
                    }
                },function (reason) {
                    return reject(reason);             //否则输出该最先被reject(reason) 的状态值；
                });
            })(i);
        }
    });
};
 -->